home *** CD-ROM | disk | FTP | other *** search
/ MacHack 1994 / MacHack 1994.toast / MacHack™ 1987-1994 / MacHack™ '90 / MacHack'90 Proceedings / John Norstad / Reusable Code / Source / vscn.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-10  |  24.5 KB  |  883 lines  |  [TEXT/MPS ]

  1. /*______________________________________________________________________
  2.  
  3.     vscn.c - Virus Scanning Module
  4.     
  5.     Copyright © 1988, 1989, 1990 Northwestern University.  Permission is 
  6.     granted to use this code in your own projects, provided you give credit 
  7.     to both John Norstad and Northwestern University in your about box or 
  8.     document.
  9.     
  10.     This module takes care of various tasks involving scanning.
  11. _____________________________________________________________________*/
  12.  
  13.  
  14. #pragma load "precompile"
  15. #include "utl.h"
  16. #include "rep.h"
  17. #include "vol.h"
  18. #include "rez.h"
  19. #include "scn.h"
  20. #include "gff.h"
  21. #include "glob.h"
  22. #include "vmsg.h"
  23. #include "misc.h"
  24. #include "prog.h"
  25. #include "main.h"
  26. #include "vscn.h"
  27.  
  28. #pragma segment vscn
  29.  
  30. /*______________________________________________________________________
  31.  
  32.     Global Variables.
  33. _____________________________________________________________________*/
  34.  
  35.  
  36. static Str255        UnlockVolName;        /* volume name of disk to be unlocked */
  37. static short        InsertedVRefNum;    /* vol ref num of inserted disk */
  38.  
  39. /*______________________________________________________________________
  40.  
  41.     vscn_CheckCancel - Check for Cancel of Scan in Progress.
  42.     
  43.     Exit:            function result = true if canceled, else false.
  44.     
  45.     This routine is called by the scanning routines to see if the operation 
  46.     has been canceled (command-period or for a click on the cancel
  47.     button).
  48. _____________________________________________________________________*/
  49.  
  50.  
  51. Boolean vscn_CheckCancel(void)
  52.  
  53. {
  54.     prog_Event();
  55.     return Canceled;
  56. }
  57.  
  58. /*______________________________________________________________________
  59.  
  60.     vscn_CheckFull - Check to See if the Report is Full.
  61.     
  62.     Entry:        report = report handle.
  63.                     slop = number of bytes to guarantee free.
  64.                     
  65.     Exit:            function result = true if cancel button selected.
  66. _____________________________________________________________________*/
  67.  
  68.  
  69. Boolean vscn_CheckFull (Handle report, short slop)
  70.  
  71. {
  72.     short                item;                    /* alert item number */
  73.     Str255            line1;                /* unplugged message */
  74.     Str255            line2;                /* plugged message */
  75.     Str255            vName;                /* vol name */
  76.  
  77.     if (rep_Full(report, slop)) {
  78.         if (!Prefs.scanningStation) {
  79.             misc_Notify(requiresAttn, true);
  80.             if (Scanning) InitCursor();
  81.             item = utl_StopAlert(repFullID, nil, 2);
  82.             if (item != ok) return true;
  83.             if (!main_Save()) return true;
  84.             misc_Update();
  85.             if (Scanning) misc_SetCursor();
  86.         };
  87.         misc_ClearReport();
  88.         misc_Update();
  89.         rep_Append(report, "\p", false, false);
  90.         rep_Append(report, "\p===========================================",
  91.             true, true);
  92.         rep_Append(report, "\p", true, true);
  93.         GetIndString(line1, strListID, repContStr);
  94.         vol_GetName(vName);
  95.         utl_PlugParams(line1, line2, &vName, nil, nil, nil);
  96.         rep_Append(report, line2, true, true);
  97.         rep_Append(report, "\p", true, true);
  98.     };
  99.     return Canceled;
  100. };
  101.  
  102. /*______________________________________________________________________
  103.  
  104.     UnlockFilter - FilterProc for Unlock Disk Alert.
  105.     
  106.     Entry:        theDialog = pointer to dialog record.
  107.                     theEvent = pointer to event record.
  108.                     
  109.     Exit:            function result = true if disk inserted.
  110.                     itemHit = 1 if disk inserted.
  111. _____________________________________________________________________*/
  112.  
  113.  
  114. static pascal Boolean UnlockFilter (DialogPtr theDialog, 
  115.     EventRecord *theEvent, short *itemHit)
  116.  
  117. {
  118.     EventRecord            theDiskEvent;        /* disk inserted event record */
  119.     short                    driveNum;            /* drive number */
  120.     ParamBlockRec        pBlock;                /* PBGetVInfo param block */
  121.     Str255                volName;                /* volume name of inserted disk */
  122.     short                    vRefNum;                /* vol ref num of inserted disk */
  123.  
  124. #pragma unused (theDialog)
  125.     
  126.     /* Filter the event. */
  127.  
  128.     if (theEvent->what == nullEvent) {
  129.         utl_WaitNextEvent(diskMask, &theDiskEvent, 0, nil);
  130.         if (theDiskEvent.what != diskEvt) return false;
  131.         driveNum = theDiskEvent.message &0xffff;
  132.         pBlock.volumeParam.ioNamePtr = &volName;
  133.         pBlock.volumeParam.ioVRefNum = driveNum;
  134.         pBlock.volumeParam.ioVolIndex = 0;
  135.         (void) PBGetVInfo(&pBlock, false);
  136.         vRefNum = pBlock.volumeParam.ioVRefNum;
  137.         if (!((pBlock.volumeParam.ioVAtrb >> 7) & 1)) {
  138.             if (!((theDiskEvent.message >> 16) & 0xffff)) {
  139.                 if (*volName == *UnlockVolName &&
  140.                     !strncmp(volName+1, UnlockVolName+1, *volName)) {
  141.                     *itemHit = 1;
  142.                     InsertedVRefNum = vRefNum;
  143.                     return true;
  144.                 };
  145.             };
  146.             if (CurScanKind == autoScan && Prefs.scanningStation &&
  147.                 !utl_DoDiskInsert(theDiskEvent.message, &InsertedVRefNum)) {
  148.                 *itemHit = 1;
  149.                 return true;
  150.             };
  151.         };
  152.         Eject(nil, driveNum);
  153.         if (CurScanKind == autoScan && vRefNum != utl_GetSysVol() && 
  154.             vRefNum != utl_GetApplVol()) 
  155.             UnmountVol(nil, vRefNum);
  156.     };
  157.     return false;
  158. }
  159.  
  160. /*______________________________________________________________________
  161.  
  162.     DrawVolList - Draw Volume List in Dialog.
  163.     
  164.     Entry:    dlog = pointer to volume list dialog.
  165.                 itemNo = item number of volume list rectangle.
  166. _____________________________________________________________________*/
  167.  
  168.  
  169. static pascal void DrawVolList (WindowPtr dlog, short itemNo)
  170.  
  171. {
  172.     short                    itemType;    /* type of dialog item */
  173.     Handle                itemHandle;    /* handle to dialog item */
  174.     Rect                    itemBox;        /* rectangle enclosing dialog item */
  175.     ListHandle            volList;        /* volume list */    
  176.     
  177.     volList = (ListHandle)((WindowPeek)dlog)->refCon;
  178.     LUpdate(dlog->visRgn , volList);
  179.     GetDItem(dlog, itemNo, &itemType, &itemHandle, &itemBox);
  180.     FrameRect(&itemBox);
  181. }
  182.  
  183. /*______________________________________________________________________
  184.  
  185.     OutlineOK - Outline OK button in Dialog.
  186.     
  187.     Entry:    dlog = pointer to volume list dialog.
  188.                 itemNo = item number of outline OK button useritem.
  189. _____________________________________________________________________*/
  190.  
  191.  
  192. static pascal void OutlineOK (WindowPtr dlog, short itemNo)
  193.  
  194. {
  195.     short                    itemType;    /* type of OK button item */
  196.     Handle                itemHandle;    /* handle to OK button item */
  197.     Rect                    itemBox;        /* rectangle enclosing OK button item */    
  198.     
  199. #pragma unused (itemNo)
  200.     
  201.     GetDItem(dlog, 1, &itemType, &itemHandle, &itemBox);
  202.     PenSize(3, 3);
  203.     InsetRect(&itemBox, -4, -4);
  204.     FrameRoundRect(&itemBox, 16, 16);
  205.     PenSize(1, 1);
  206. }
  207.  
  208. /*______________________________________________________________________
  209.  
  210.     VolListFilter - Filter Proc for Volume List Dialog.
  211.     
  212.     Entry:    dlog = pointer to volume list dialog.
  213.                 theEvent = pointer to event record.
  214.                 
  215.     Exit:        itemHit = 3 if hit in volume list rectangle.
  216.                           = 1 if enter or return key pressed.
  217.                           = 2 if command period pressed.
  218.                 function result = true if hit in volume list rectangle
  219.                     or enter or return key or command period pressed.
  220. _____________________________________________________________________*/
  221.  
  222. static pascal Boolean VolListFilter (WindowPtr dlog, EventRecord *theEvent,
  223.     short *itemHit)
  224.     
  225. {
  226.     short            key;            /* ascii code of key pressed */
  227.     Point            where;        /* location of mouse down */
  228.     short            itemType;    /* type of dialog item */
  229.     Handle        itemHandle;    /* handle to dialog item */
  230.     Rect            itemBox;        /* rectangle enclosing dialog item */    
  231.     ListHandle    volList;        /* volume list */
  232.  
  233.     SetPort(dlog);
  234.     switch (theEvent->what) {
  235.         case mouseDown:
  236.             where = theEvent->where;
  237.             GlobalToLocal(&where);
  238.             GetDItem(dlog, 3, &itemType, &itemHandle, &itemBox);
  239.             if (PtInRect(where, &itemBox)) {
  240.                 volList = (ListHandle)((WindowPeek)dlog)->refCon;
  241.                 LClick(where, theEvent->modifiers, volList);
  242.                 *itemHit = 3;
  243.                 return true;
  244.             };
  245.             break;
  246.         case keyDown:
  247.         case autoKey:
  248.             key = theEvent->message & charCodeMask;
  249.             if (key == returnKey || key == enterKey) {
  250.                 *itemHit = 1;
  251.                 return true;
  252.             };
  253.             if (key == '.' && theEvent->modifiers & cmdKey) {
  254.                 *itemHit = 2;
  255.                 return true;
  256.             };
  257.             break;
  258.     };
  259.     return false;
  260. }
  261.  
  262. /*______________________________________________________________________
  263.  
  264.     FolderFilter - Folder Filter Function for Modified Get File Dialog.
  265.     
  266.     Entry:    pBlock = pointer to GetFileInfo param block.
  267.                 
  268.     Exit:        function result = true if file, false if folder.
  269.     
  270.     This function is used by the vscn_DoScan function below to process the
  271.     "Folder" menu item in the Scan and Disinfect menus.  It
  272.     filters out all but the folder names in the modified get file
  273.     dialog.
  274. _____________________________________________________________________*/
  275.  
  276.  
  277. static pascal Boolean FolderFilter (ParmBlkPtr pBlock)
  278.  
  279. {
  280.     return (pBlock->fileParam.ioFlAttrib & 0x10) == 0;
  281. }
  282.  
  283. /*______________________________________________________________________
  284.  
  285.     vscn_DoScan - Process a Scan or Disinfect Operation.
  286.     
  287.     Entry:        scanKind = type of scan (volScan, foldScan, fileScan, 
  288.                         etc.)
  289.                     scanOp = scanning operation (checkOp or disinfectOp).
  290. _____________________________________________________________________*/
  291.  
  292.  
  293. void vscn_DoScan (ScanKind scanKind, ScanOp scanOp)
  294.  
  295. {
  296.     unsigned char        saveHilite[numControls];
  297.                                             /* saved control hilite states */
  298.     short                    i;                /* loop index */
  299.     short                    vRefNum;        /* vol ref num of vol containing object
  300.                                                 being scanned */
  301.     long                    dirID;        /* dir id of folder if folder scan */
  302.     char                    *fName;        /* ptr to file name if file scan */
  303.     short                    fVRefNum;    /* wd or vol ref num of folder or vol
  304.                                                 containing file if file scan */
  305.     scn_DoFilePtr        doFile;        /* ptr to do file function for scan */                                                
  306.     Boolean                infected;    /* true if infected file found */
  307.     Boolean                sysInfected;  /* true if infected file found in
  308.                                                   currently active system folder */
  309.     Handle                h;                /* handle to DLOG resource */
  310.     Point                    where;        /* loctn of get file or folder dialog */
  311.     SFReply                reply;        /* reply from gff_Get */
  312.     Boolean                wait;            /* true to wait for disk insertion */
  313.     short                    volInx;        /* index in VCB queue */
  314.     HParamBlockRec        vBlock;        /* vol info param block */
  315.     DrvQEl                *curDrive;    /* ptr to drive queue element */
  316.     unsigned char        flagByte;    /* drive queue el flag byte */
  317.     short                    driveNum;    /* drive number */
  318.     Boolean                firstDisk;    /* true if asking for first disk */
  319.     OSErr                    rCode;        /* result code */
  320.     short                    unlockButton;    /* button chosen in unlock alert */
  321.     WDPBRec                wdBlock;        /* working directory info param block */
  322.     FCBPBRec                fcbBlock;    /* FCB info param block */
  323.     char                    sysFileName[30];    /* system file name */
  324.     DialogPtr            dlog;            /* pointer to vol list dialog */
  325.     Rect                    dlogRect;    /* dialog rectangle */
  326.     short                    itemHit;        /* item number hit in vol list dialog */
  327.     short                    itemType;    /* type of dialog item */
  328.     Handle                itemHandle;    /* handle to dialog item */
  329.     Rect                    itemBox;        /* rectangle enclosing dialog item */
  330.     ListHandle            volList;        /* volume list */
  331.     Rect                    rView;        /* rectangle enclosing volume list */
  332.     Rect                    dataBounds;    /* vol list dimensions */
  333.     Point                    volPt;        /* vol list cell */
  334.     char                    volName[30];    /* vol name */
  335.     Handle                vrn;            /* handle to list of vRefNums */
  336.     short                    vrnSize;        /* size of list of vRefNums */
  337.     short                    vrnInx;        /* cur index in list of vRefNums */
  338.     short                    lastVrn;        /* index in list of vRefNums following last
  339.                                                 entry */
  340.     GrafPtr                thePort;        /* saved grafport */
  341.     short                    strInx;        /* index of STR# resource string */
  342.     char                    scanOpWord[20];    /* "scanned" or "disinfected" */
  343.     Str255                prompt1;        /* unplugged prompt string for get
  344.                                                 file/folder dialog */
  345.     Str255                prompt2;        /* plugged prompt string for get 
  346.                                                 file/folder dialog */
  347.     
  348.     /* Remember the scan kind in a global variable, and initialize 
  349.         Canceled to false. */
  350.     
  351.     CurScanKind = scanKind;
  352.     Canceled = false;
  353.     
  354.     /* Get currently selected volume. */
  355.  
  356.     (void) vol_GetSel(&vRefNum);
  357.     
  358.     /* Get pointer to do file function. */
  359.     
  360.     switch (scanOp) {
  361.         case checkOp:
  362.             doFile = misc_ListDirectory;
  363.             break;
  364.         case disinfectOp:
  365.             doFile = misc_ListDirectory;
  366.             break;
  367.     };
  368.     
  369.     /* Initialize depending on type of scan.  Present open file, open folder,
  370.         or open file/folder dialog if necessary.  Get the following info:
  371.         
  372.         vRefNum = vol ref num of vol containing object to be scanned.
  373.         dirID = dir id of folder if folder scan.
  374.         fName = pointer to file name if file scan.
  375.         fVRefNum = vol or wd ref num of vol or folder containing file
  376.             if file scan. */
  377.         
  378.     dirID = 0;
  379.     fName = "\p";
  380.     fVRefNum = 0;
  381.     wait = false;
  382.     
  383.     if (CurScanKind == fileScan || CurScanKind == foldScan || 
  384.         CurScanKind == fileFoldScan || CurScanKind == volSetScan) {
  385.         switch (scanOp) {
  386.             case checkOp:
  387.                 strInx = scannedWord;
  388.                 break;
  389.             case disinfectOp:
  390.                 strInx = disinfectedWord;
  391.                 break;
  392.         };
  393.         GetIndString(scanOpWord, strListID, strInx);
  394.     };
  395.     
  396.     switch (CurScanKind) {
  397.     
  398.         case allScan:
  399.         
  400.             volInx = 0;
  401.             break;
  402.             
  403.         case volScan:
  404.         
  405.             break;
  406.             
  407.         case fileScan:
  408.         case foldScan:
  409.         case fileFoldScan:
  410.         
  411.             /* Set standard file dialog default vol to currently selected vol. */
  412.             
  413.             if (-vRefNum != *(short*)SFSaveDisk) {
  414.                 *(short*)SFSaveDisk = -vRefNum;
  415.                 if (!OldRom) *(long*)CurDirStore = fsRtDirID;
  416.             };
  417.             
  418.             /* Load the proper get file dialog and center it. */
  419.             
  420.             h = GetResource('DLOG', 
  421.                 (CurScanKind == fileScan) ? getFileID : getFFID);
  422.             HNoPurge(h);
  423.             utl_CenterDlogRect(*(Rect**)h, MenuPick);
  424.             where = **(Point**)h;
  425.             
  426.             /* Present the dialog. */
  427.             
  428.             switch (CurScanKind) {
  429.                 case fileScan:
  430.                     strInx = getFilePrompt;
  431.                     break;
  432.                 case foldScan:
  433.                     strInx = getFoldPrompt;
  434.                     break;
  435.                 case fileFoldScan:
  436.                     strInx = getFFPrompt;
  437.                     break;
  438.             };
  439.             GetIndString(prompt1, strListID, strInx);
  440.             utl_PlugParams(prompt1, prompt2, scanOpWord, nil, nil, nil);
  441.             switch (CurScanKind) {
  442.                 case fileScan:
  443.                     SFPGetFile(where, prompt2, nil, -1, nil, nil, &reply,
  444.                         getFileID, nil);
  445.                     break;
  446.                 case foldScan:
  447.                     gff_Get(&where, prompt2, FolderFilter, -1, nil, &reply, getFFID);
  448.                     break;
  449.                 case fileFoldScan:
  450.                     gff_Get(&where, prompt2, nil, -1, nil, &reply, getFFID);
  451.                     break;
  452.             };
  453.             misc_Update();
  454.             
  455.             /* Clean up and get out if the user clicked on the cancel button. */
  456.             
  457.             HPurge(h);
  458.             if (!reply.good) return;
  459.             
  460.             /* Set CurScanKind = kind of scan (file or folder), and
  461.                 set other variables. */
  462.                 
  463.             switch (CurScanKind) {
  464.                 case fileScan:
  465.                     /* call GetWDInfo to get vRefNum = ref num of vol containing 
  466.                         file */
  467.                     wdBlock.ioNamePtr = nil;
  468.                     wdBlock.ioVRefNum = reply.vRefNum;
  469.                     wdBlock.ioWDIndex = 0;
  470.                     wdBlock.ioWDProcID = 0;
  471.                     PBGetWDInfo(&wdBlock, false);
  472.                     vRefNum = wdBlock.ioWDVRefNum;
  473.                     fName = reply.fName;
  474.                     fVRefNum = reply.vRefNum;
  475.                     break;
  476.                 case foldScan:
  477.                     if (reply.fType == fsRtDirID) CurScanKind = volScan;
  478.                     vRefNum = reply.vRefNum;
  479.                     break;
  480.                 case fileFoldScan:
  481.                     CurScanKind = *reply.fName ? fileScan : foldScan;
  482.                     if (CurScanKind == fileScan) {
  483.                         vRefNum = reply.version;
  484.                         fName = reply.fName;
  485.                         fVRefNum = reply.vRefNum;
  486.                     } else {
  487.                         if (reply.fType == fsRtDirID) CurScanKind = volScan;
  488.                         vRefNum = reply.vRefNum;
  489.                     };
  490.             };
  491.             if (CurScanKind == foldScan) dirID = reply.fType;
  492.             break;
  493.             
  494.         case autoScan:
  495.         
  496.             /* Check drives 1 and 2 (internal and external floppy drives).
  497.                 Eject them if they are not empty.  See IM IV-181.
  498.                 
  499.                 Set wait=true and firstDisk=true to wait for insertion
  500.                 of first disk. */
  501.                 
  502.             firstDisk = wait = true;
  503.             curDrive = (DrvQEl*)(GetDrvQHdr())->qHead;
  504.             while (curDrive) {
  505.                 driveNum = curDrive->dQDrive;
  506.                 if (driveNum == 1 || driveNum == 2) {
  507.                     flagByte = *((Ptr)curDrive-3);
  508.                     if (flagByte && flagByte < 0xfc) {
  509.                         misc_CheckEject(driveNum);
  510.                         Eject(nil, driveNum);
  511.                     };
  512.                 };
  513.                 curDrive = (DrvQEl*)curDrive->qLink;
  514.             };
  515.             break;
  516.     
  517. /* Set wait=true to wait for a disk insertion.
  518.     Check drives 1 and 2 (internal and external floppy drives).
  519.     If neither is empty, eject one of them (eject drive 2 if it
  520.     exists).  See IM IV-181.
  521.             
  522.             firstDisk = wait = true;
  523.             drive2 = false;
  524.             curDrive = (DrvQEl*)(GetDrvQHdr())->qHead;
  525.             while (curDrive) {
  526.                 driveNum = curDrive->dQDrive;
  527.                 if (driveNum == 1 || driveNum == 2) {
  528.                     flagByte = *((Ptr)curDrive-3);
  529.                     if (!flagByte || flagByte >= 0xfc) break;
  530.                     drive2 = driveNum == 2;
  531.                 };
  532.                 curDrive = (DrvQEl*)curDrive->qLink;
  533.             };
  534.             if (!curDrive) {
  535.                 drRefNum = drive2 ? 2 : 1;
  536.                 Eject(nil, drRefNum);
  537.             };
  538.             break;
  539.             
  540.  */
  541.             
  542.         case sysFileScan:
  543.         
  544.             CurScanKind = fileScan;
  545.             vRefNum = SysVol;
  546.             fVRefNum = utl_GetSysWD();
  547.             fcbBlock.ioVRefNum = 0;
  548.             fcbBlock.ioFCBIndx = 0;
  549.             fcbBlock.ioRefNum = SysRefNum;
  550.             fcbBlock.ioNamePtr = sysFileName;
  551.             PBGetFCBInfo(&fcbBlock, false);
  552.             fName = sysFileName;
  553.             break;
  554.             
  555.         case sysFoldScan:
  556.         
  557.             vRefNum = SysVol;
  558.             if (utl_VolIsMFS(vRefNum) || SysDirID == fsRtDirID) {
  559.                 CurScanKind = volScan;
  560.             } else {
  561.                 CurScanKind = foldScan;
  562.                 dirID = SysDirID;
  563.             };
  564.             break;
  565.             
  566.         case volSetScan:
  567.         
  568.             /* Initialize the dialog. */
  569.             
  570.             GetPort(&thePort);
  571.             dlog = GetNewDialog(volListID, nil, (WindowPtr)-1);
  572.             dlogRect = dlog->portRect;
  573.             utl_CenterDlogRect(&dlogRect, MenuPick);
  574.             MoveWindow(dlog, dlogRect.left, dlogRect.top, false);
  575.             GetDItem(dlog, 3, &itemType, &itemHandle, &rView);
  576.             SetDItem(dlog, 3, itemType, (Handle)DrawVolList, &rView);
  577.             GetDItem(dlog, 4, &itemType, &itemHandle, &itemBox);
  578.             SetDItem(dlog, 4, itemType, (Handle)OutlineOK, &itemBox);
  579.             GetDItem(dlog, 5, &itemType, &itemHandle, &itemBox);
  580.             GetIText(itemHandle, prompt1);
  581.             utl_PlugParams(prompt1, prompt2, scanOpWord, nil, nil, nil);
  582.             SetIText(itemHandle, prompt2);
  583.             
  584.             /* Initialize an empty volume list. */
  585.             
  586.             InsetRect(&rView, 1, 1);
  587.             rView.right -= 15;
  588.             SetRect(&dataBounds, 0, 0, 1, 0);
  589.             SetPt(&volPt, 0, 0);
  590.             volList = LNew (&rView, &dataBounds, volPt, 0, dlog, 
  591.                 false, false, false, true);
  592.             (**volList).selFlags = lNoExtend | lUseSense;
  593.             ((WindowPeek)dlog)->refCon = volList;
  594.             
  595.             /* Fill the volume list with the names of all the online volumes.
  596.                 Also record their vRefNums in the vrn array. */
  597.                 
  598.             vrn = NewHandle(20);
  599.             vrnSize = 20;
  600.             vrnInx = 0;
  601.             volInx = 0;
  602.             vBlock.volumeParam.ioNamePtr = volName;
  603.             while (true) {
  604.                 vBlock.volumeParam.ioVolIndex = ++volInx;
  605.                 vBlock.volumeParam.ioVRefNum = 0;
  606.                 if (PBHGetVInfo(&vBlock, false)) break;
  607.                 if (vBlock.volumeParam.ioVDrvInfo) {
  608.                     LAddRow(1, volPt.v, volList);
  609.                     LSetCell(volName+1, *volName, volPt, volList);
  610.                     volPt.v++;
  611.                     if (vrnInx >= vrnSize) {
  612.                         vrnSize += 20;
  613.                         SetHandleSize(vrn, vrnSize);
  614.                     };
  615.                     *(short*)(*vrn + vrnInx) = vBlock.volumeParam.ioVRefNum;
  616.                     vrnInx += 2;
  617.                 };
  618.             };
  619.             
  620.             /* Show the window and process events. */
  621.             
  622.             LDoDraw(true, volList);
  623.             ShowWindow((WindowPtr)dlog);
  624.             do {
  625.                 ModalDialog(VolListFilter, &itemHit);
  626.             } while (itemHit != ok && itemHit != cancel);
  627.             
  628.             /* Collapse the list of vRefNums to just those that have
  629.                 been selected by the user. */
  630.             
  631.             vrnInx = 0;
  632.             volPt.v = 0;
  633.             while (LGetSelect(true, &volPt, volList)) {
  634.                 *(short*)(*vrn + vrnInx) = *(short*)(*vrn + (volPt.v<<1));
  635.                 vrnInx += 2;
  636.                 volPt.v++;
  637.             };
  638.             lastVrn = vrnInx;
  639.             vrnInx = 0;
  640.             
  641.             /* Dispose of the volume list and the dialog, leaving just the
  642.                 vRefNum list. */
  643.             
  644.             LDispose(volList);
  645.             DisposDialog(dlog);
  646.             SetPort(thePort);
  647.             misc_Update();
  648.             
  649.             /* If the cancel button was pressed, or if there are no selected
  650.                 volumes in the list, dispose of the vRefNum list and return. */
  651.                 
  652.             if (itemHit == cancel || !lastVrn) {
  653.                 DisposHandle(vrn);
  654.                 return;
  655.             };
  656.             break;
  657.             
  658.     };
  659.     
  660.     HiliteMenu(0);
  661.     
  662.     /* Set selected volume and process resulting update event. */
  663.     
  664.     vol_SetSel(vRefNum, true);
  665.     misc_Update();
  666.     
  667.     /* Start the beachball spinning. */
  668.     
  669.     Scanning = true;
  670.     misc_SetCursor();
  671.  
  672.     /* Save old hilite states for all buttons.  Unhilite all buttons
  673.         except for Cancel.  Also unhilite the report scroll bar. */
  674.  
  675.     for (i=0; i<numControls; i++) {
  676.         saveHilite[i] = (**Controls[i]).contrlHilite;
  677.         if (i+firstControl == cancelID) {
  678.             HiliteControl(Controls[i], 0);
  679.         } else {
  680.             HiliteControl(Controls[i], 255);
  681.         };
  682.     };
  683.     main_SetPort();
  684.     rep_Activate(Report, false);
  685.                 
  686.     /* Main loop - do one volume at a time. */
  687.     
  688.     while (true) {
  689.     
  690.         /* If wait=true wait for the user to insert the next floppy. */
  691.         
  692.         if (wait) {
  693.             main_WaitInsert(firstDisk, &vRefNum, &Canceled);
  694.             firstDisk = false;
  695.             if (Canceled) {
  696.                 vol_Verify();
  697.                 break;
  698.             };
  699.             vol_SetSel(vRefNum, false);
  700.             misc_Update();
  701.         };
  702.         
  703.         /* If allScan advance to next volume. */
  704.         
  705.         if (CurScanKind == allScan) {
  706.             vBlock.volumeParam.ioNamePtr = nil;
  707.             while (true) {
  708.                 vBlock.volumeParam.ioVolIndex = ++volInx;
  709.                 vBlock.volumeParam.ioVRefNum = 0;
  710.                 if (rCode = PBHGetVInfo(&vBlock, false)) break;
  711.                 if (vBlock.volumeParam.ioVDrvInfo) break;
  712.             };
  713.             if (rCode) break;
  714.             vRefNum = vBlock.volumeParam.ioVRefNum;
  715.             vol_SetSel(vRefNum, false);
  716.             misc_Update();
  717.         };
  718.         
  719.         /* If volSetScan advance to next volume. */
  720.         
  721.         if (CurScanKind == volSetScan) {
  722.             if (vrnInx >= lastVrn) break;
  723.             vRefNum = *(short*)(*vrn + vrnInx);
  724.             vrnInx += 2;
  725.             vol_SetSel(vRefNum, false);
  726.             misc_Update();
  727.         };
  728.     
  729.         /* On a disinfect scan, check to make sure the volume is unlocked.
  730.             If it's locked, eject the disk and put up an alert asking the
  731.             user to unlock and reinsert it. */
  732.             
  733.         if (scanOp == disinfectOp) {
  734.             vBlock.volumeParam.ioNamePtr = UnlockVolName;
  735.             vBlock.volumeParam.ioVRefNum = vRefNum;
  736.             vBlock.volumeParam.ioVolIndex = 0;
  737.             (void) PBHGetVInfo(&vBlock, false);
  738.             if ((vBlock.volumeParam.ioVAtrb >> 7) & 1) {
  739.                 Eject(nil, vRefNum);
  740.                 if (CurScanKind == autoScan && vRefNum != utl_GetSysVol() && 
  741.                     vRefNum != utl_GetApplVol()) 
  742.                     UnmountVol(nil, vRefNum);
  743.                 misc_Notify(requiresAttn, true);
  744.                 InitCursor();
  745.                 if (CurScanKind == autoScan && Prefs.scanningStation) {
  746.                     unlockButton = utl_StopAlert(unlockSSID, UnlockFilter, 0);
  747.                 } else {
  748.                     unlockButton = utl_StopAlert(unlockID, UnlockFilter, 2);
  749.                 };
  750.                 misc_SetCursor();
  751.                 if (unlockButton == 2) {
  752.                     vol_Verify();
  753.                     Canceled = true;
  754.                     break;
  755.                 };
  756.                 vRefNum = InsertedVRefNum;
  757.                 vol_SetSel(vRefNum, false);
  758.                 misc_Update();
  759.                 if (Canceled) break;
  760.             };
  761.         };
  762.         
  763.         /* Check for report full. */
  764.         
  765.         if (vscn_CheckFull(Report, 6000)) break; 
  766.             
  767.         /* Output report header. */
  768.         
  769.         vmsg_Begin(scanOp == disinfectOp, dirID, 
  770.             fName, fVRefNum, vRefNum, RectList[counterRect].top,
  771.             RectList[counterRect].right);
  772.         
  773.         /* Scan the volume. */
  774.         
  775.         Canceled = scn_Vol(vRefNum, dirID, fName, fVRefNum, doFile,
  776.             (long)Report, vscn_CheckCancel, &RectList[foldNameRect], 
  777.             &RectList[fileNameRect], &RectList[thermRect], systemFont, 0); 
  778.         
  779.         /* Redraw the thermometer frame. */
  780.         
  781.         FrameRect(&RectList[thermRect]);
  782.         
  783.         /* Output report summary. */
  784.         
  785.         vmsg_End(scanOp == disinfectOp, Canceled, &infected, &sysInfected);
  786.         RepInfected |= infected;
  787.         if (scanOp == disinfectOp) SysInfect |= sysInfected;
  788.         
  789.         /* Break out of loop if not allScan or autoScan or volSetScan, 
  790.             or if canceled. */
  791.         
  792.         if (CurScanKind != allScan && CurScanKind != autoScan && 
  793.             CurScanKind != volSetScan) break;
  794.         if (Canceled) break;
  795.         
  796.         /* If autoscan, eject floppy.  Also unmount it if it's not the
  797.             current system volume or the volume containing the current 
  798.             application.  Set wait=true to wait for the user to insert the
  799.             next floppy. */
  800.             
  801.         if (CurScanKind == autoScan) {
  802.             misc_CheckEject(vRefNum);
  803.             Eject(nil, vRefNum);
  804.             if (vRefNum != utl_GetSysVol() && vRefNum != utl_GetApplVol()) 
  805.                 UnmountVol(nil, vRefNum);
  806.             wait = true;
  807.         };
  808.     
  809.     };
  810.     
  811.     Scanning = false;
  812.     
  813.     /* Restore saved hilite states. 
  814.         Disable the Disinfect button if requested by vrep_Repair.
  815.         Also hilite the scroll bar. */
  816.     
  817.     for (i=0; i<numControls; i++) {
  818.         if (i == disinfectID-firstControl) {
  819.             HiliteControl(Controls[i], DisableDisinfect ? 255 : 
  820.                 saveHilite[i]);
  821.         } else {
  822.             HiliteControl(Controls[i], saveHilite[i]);
  823.         };
  824.     };
  825.     rep_Activate(Report, true);
  826.     
  827.     /* Verify the current volume. */
  828.     
  829.     vol_Verify();
  830.     
  831.     /* If volSetScan, dispose of vRefNum list. */
  832.  
  833.     if (CurScanKind == volSetScan) {
  834.         DisposHandle(vrn);
  835.     };
  836.     
  837.     /* Restore the cursor. */
  838.     
  839.     misc_SetCursor();
  840. }
  841.  
  842. /*______________________________________________________________________
  843.  
  844.     vscn_DoButton - Process a Mouse Down on One of the Two Scanning Buttons
  845.     
  846.     Entry:        scanOp = scanning operation (checkOp or disinfectOp).
  847.                     modifiers = command key modifiers.
  848. _____________________________________________________________________*/
  849.  
  850.  
  851. void vscn_DoButton (ScanOp scanOp, short modifiers)
  852.  
  853. {
  854.     Boolean                optionDown;    /* true if option key held down */
  855.     Boolean                cmdDown;        /* true if command key held down */
  856.     short                    scanKind;    /* kind of scan */
  857.  
  858.     /* Check for modifier keys. */
  859.     
  860.     optionDown = (modifiers & optionKey) != 0;
  861.     cmdDown = (modifiers & cmdKey) != 0;
  862.     
  863.     /* Determine kind of scan. */
  864.     
  865.     if (optionDown) {
  866.         if (cmdDown) {
  867.             scanKind = allScan;                /* option and command */
  868.         } else {
  869.             scanKind = fileFoldScan;        /* option */
  870.         };
  871.     } else {
  872.         if (cmdDown) {
  873.             scanKind = autoScan;                /* command */
  874.         } else {
  875.             scanKind = volScan;                /* no modifer keys */
  876.         };
  877.     };
  878.     
  879.     /* Call vscn_DoScan to do the scan. */
  880.     
  881.     vscn_DoScan(scanKind, scanOp);
  882. }
  883.